#include "file_index.h"
#include "utils_log.h"
#include "utils_file_ex.h" // 用于 LoadFileWithBackup, SaveFileWithBackup
#include <nlohmann/json.hpp>
#include <filesystem>
#include <fstream>
#include <unordered_set>
#include <iomanip>
#include <random>
#include <sstream>
#include <algorithm>    // 用于 std::transform, std::any_of, std::remove_if
#include <system_error> // 用于 std::error_code
#include <ctime>        // 用于 std::time

namespace fs = std::filesystem;

namespace El {
namespace FileManager {

FileIndex::FileIndex(std::string indexFilePath)
    : indexFilePath_(std::move(indexFilePath)), indexData_(nlohmann::json::array())
{
}

bool FileIndex::Initialize()
{
    // 确保索引文件的目录存在
    fs::path filePath(indexFilePath_);
    fs::path dirPath = filePath.parent_path();
    if (!dirPath.empty() && !fs::exists(dirPath)) {
        std::error_code ec;
        if (!fs::create_directories(dirPath, ec) || ec) { // 检查错误码
            EL_ERROR("为索引文件 {} 创建目录 {} 失败: {}", indexFilePath_, dirPath.string(), ec.message());
            return false;
        }
    }
    return LoadIndex();
}

bool FileIndex::LoadIndex()
{
    std::lock_guard<std::mutex> lock(mutex_); // 加载期间加锁

    std::vector<uint8_t> content;
    if (Utils::LoadFileWithBackup(indexFilePath_, content)) {
        try {
            // 允许异常以避免在文件为 0 字节时解析空内容
            if (content.empty()) {
                EL_WARN("索引文件 {} 为空。初始化为空数组。", indexFilePath_);
                indexData_ = nlohmann::json::array();
            } else {
                indexData_ = nlohmann::json::parse(content);
            }

            if (CheckIndexIntegrity(indexData_)) {
                EL_INFO("成功加载并验证索引: {}", indexFilePath_);
                return true;
            } else {
                EL_ERROR("索引完整性检查失败: {}. 重置为空。", indexFilePath_);
                indexData_ = nlohmann::json::array(); // 失败时重置为空
                // 尝试保存现在为空的索引以创建有效的文件/备份
                return SaveIndex(); // 返回保存空索引的状态
            }
        } catch (const nlohmann::json::parse_error &e) {
            EL_ERROR("从 {} 解析索引 JSON 失败: {}. 重置为空。", indexFilePath_, e.what());
            indexData_ = nlohmann::json::array(); // 失败时重置为空
            // 尝试保存现在为空的索引以创建有效的文件/备份
            return SaveIndex();                        // 返回保存空索引的状态
        } catch (const nlohmann::json::exception &e) { // 捕获其他 json 异常
            EL_ERROR("处理 {} 时 JSON 库异常: {}. 重置为空。", indexFilePath_, e.what());
            indexData_ = nlohmann::json::array();
            return SaveIndex();
        }
    } else {
        // LoadFileWithBackup 在文件和备份都失败时内部记录错误
        EL_WARN("加载索引文件（及备份）{} 失败。初始化为空索引。", indexFilePath_);
        indexData_ = nlohmann::json::array(); // 初始化为空
        // 尝试保存新的空索引以创建有效的文件/备份
        return SaveIndex(); // 返回保存空索引的状态
    }
}

bool FileIndex::SaveIndex()
{
    // 此方法假设调用者（或之前的内部调用）在必要时持有 mutex_。
    // 在当前设计中，公共方法在调用 SaveIndex 之前获取锁。
    try {
        std::string indexStr = indexData_.dump(4); // 美化打印 JSON
        std::vector<uint8_t> indexBytes(indexStr.begin(), indexStr.end());

        if (!Utils::SaveFileWithBackup(indexFilePath_, indexBytes)) {
            // SaveFileWithBackup 记录的错误
            return false;
        }

        EL_DEBUG("成功保存带备份的索引文件: {}", indexFilePath_);
        return true;
    } catch (const nlohmann::json::exception &e) {
        EL_ERROR("为 {} 将索引转储为字符串时 JSON 库异常: {}", indexFilePath_, e.what());
        return false;
    }
}

bool FileIndex::CheckIndexIntegrity(const nlohmann::json &indexData)
{
    // 从 FileIndexManager::CheckIndexIntegrity 迁移的实现
    if (!indexData.is_array()) {
        EL_ERROR("索引完整性检查失败: {} 中的根不是数组", indexFilePath_);
        return false;
    }

    std::unordered_set<std::string> ids; // 检查重复 ID

    for (const auto &item : indexData) {
        if (!item.is_object()) {
            EL_WARN("{} 中的完整性检查失败: 条目不是对象: {}", indexFilePath_, item.dump(2)); // 更简洁的转储
            return false;
        }

        // 检查必需字段和类型
        if (!item.contains("id") || !item["id"].is_string() || item["id"].get<std::string>().empty()) {
            EL_WARN("{} 中的完整性检查失败: 缺少、无效或空的 'id': {}", indexFilePath_, item.dump(2));
            return false;
        }
        std::string currentId = item["id"].get<std::string>();
        if (!ids.insert(currentId).second) {
            EL_WARN("{} 中的完整性检查失败: 找到重复的 'id': {}", indexFilePath_, item.dump(2));
            return false;
        }

        if (!item.contains("name") || !item["name"].is_string()) {
            // 允许空名称
            // EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'name': {}", indexFilePath_, item.dump(2));
            // return false;
        }
        if (!item.contains("type") || !item["type"].is_string()) {
            EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'type': {}", indexFilePath_, item.dump(2));
            return false;
        } else {
            std::string type = item["type"].get<std::string>();
            if (type != "audio" && type != "image" && type != "video" && type != "unknown") { // 允许 "unknown"
                EL_WARN("{} 中的完整性检查失败: 未知的 'type': {}", indexFilePath_, item.dump(2));
                // 允许未知类型，也许记录方式不同？暂时通过。
                // return false;
            }
        }
        if (!item.contains("path") || !item["path"].is_string() || item["path"].get<std::string>().empty()) {
            EL_WARN("{} 中的完整性检查失败: 缺少、无效或空的 'path': {}", indexFilePath_, item.dump(2));
            return false;
        }
        // 可选：检查路径是否存在？如果文件可能远程/临时不可用，可能较慢或不希望这样做。
        // if (!fs::exists(item["path"].get<std::string>())) {
        //     EL_WARN("{} 中的完整性检查警告: 路径不存在: {}", indexFilePath_, item.dump());
        // }

        if (!item.contains("size") || !item["size"].is_number_unsigned()) {
            EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'size': {}", indexFilePath_, item.dump(2));
            return false;
        }
        if (!item.contains("is_deleted") || !item["is_deleted"].is_boolean()) {
            EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'is_deleted': {}", indexFilePath_, item.dump(2));
            return false;
        }
        if (!item.contains("last_access") || !item["last_access"].is_number_integer()) {
            EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'last_access': {}", indexFilePath_, item.dump(2));
            return false;
        }
        
        // 检查 origin 字段
        if (!item.contains("origin") || !item["origin"].is_string()) {
            EL_WARN("{} 中的完整性检查失败: 缺少或无效的 'origin': {}", indexFilePath_, item.dump(2));
            return false;
        } else {
            std::string origin = item["origin"].get<std::string>();
            if (origin != "preset" && origin != "user") {
                EL_WARN("{} 中的完整性检查失败: 无效的 'origin' 值 '{}': {}", 
                         indexFilePath_, origin, item.dump(2));
                return false;
            }
        }
    }

    return true;
}

// --- 静态辅助方法 ---

std::string FileIndex::GenerateUniqueId()
{
    // 从 FileIndexManager::GenerateUniqueId 迁移的实现
    static std::random_device rd;
    static std::mt19937_64 gen(rd());
    static std::uniform_int_distribution<uint64_t> dis;

    std::stringstream ss;
    // 生成两个 64 位随机数，组合成 128 位十六进制字符串（32 个字符）
    ss << std::hex << std::setfill('0') << std::setw(16) << dis(gen);
    ss << std::hex << std::setfill('0') << std::setw(16) << dis(gen);
    return ss.str();
}

std::string FileIndex::GuessFileType(const std::string &filePath)
{
    // 从 FileIndexManager::GuessFileType 迁移的实现
    fs::path p(filePath);
    std::string extension = p.has_extension() ? p.extension().string() : "";

    std::transform(extension.begin(), extension.end(), extension.begin(),
                   [](unsigned char c) { return static_cast<char>(std::tolower(c)); }); // 确保 char 转换

    const static std::unordered_set<std::string> audioExtensions = {".mp3", ".wav", ".ogg",  ".flac",
                                                                    ".aac", ".m4a", ".opus", ".wma"};
    if (audioExtensions.count(extension))
        return "audio";

    const static std::unordered_set<std::string> imageExtensions = {".jpg", ".jpeg", ".png",  ".gif", ".bmp",
                                                                    ".svg", ".webp", ".tiff", ".ico"};
    if (imageExtensions.count(extension))
        return "image";

    const static std::unordered_set<std::string> videoExtensions = {".mp4", ".avi", ".mov",  ".mkv", ".webm",
                                                                    ".wmv", ".flv", ".mpeg", ".mpg", ".3gp"};
    if (videoExtensions.count(extension))
        return "video";

    // 暂时保留未知，让具体逻辑在需要时决定默认值
    EL_DEBUG("路径 '{}' 的未知文件扩展名 '{}'，分类为未知。", filePath, extension);
    return "unknown";
}

// --- 实例方法 ---

bool FileIndex::AddFileInfo(const FileInfo &fileInfo)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // 检查重复 ID
    for (const auto &item : indexData_) {
        if (item.value("id", "") == fileInfo.id) {
            EL_ERROR("文件 ID {} 已存在于索引 {} 中", fileInfo.id, indexFilePath_);
            return false;
        }
    }

    indexData_.push_back(fileInfo.ToJson());
    return SaveIndex();
}

bool FileIndex::UpdateFileInfo(const FileInfo &fileInfo)
{
    std::lock_guard<std::mutex> lock(mutex_);
    bool found = false;

    for (auto &item : indexData_) {
        if (item.value("id", "") == fileInfo.id) {
            item = fileInfo.ToJson();
            found = true;
            break;
        }
    }

    if (!found) {
        EL_ERROR("在索引 {} 中未找到要更新的文件 ID {}", indexFilePath_, fileInfo.id);
        return false;
    }

    return SaveIndex();
}

bool FileIndex::GetFileInfo(const std::string &fileId, FileInfo &outInfo)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (const auto &item : indexData_) {
        if (item.value("id", "") == fileId) {
            auto parsedInfo = FileInfo::FromJson(item);
            if (parsedInfo) {
                outInfo = *parsedInfo;
                return true;
            } else {
                EL_WARN("从索引 {} 解析文件信息失败，ID {}: {}", indexFilePath_, fileId, item.dump(2));
                // 在解析错误的情况下继续搜索？还是返回 false？
                // 暂时返回 false，因为此 ID 的数据已损坏。
                return false;
            }
        }
    }
    return false; // 未找到
}

std::vector<FileInfo> FileIndex::GetFileList(FileType type, bool includeDeleted)
{
    std::lock_guard<std::mutex> lock(mutex_);
    std::vector<FileInfo> result;

    auto filterFile = [this, type, includeDeleted](const nlohmann::json &item) -> std::optional<FileInfo> {
        bool isDeleted = item.value("is_deleted", false);
        if (!includeDeleted && isDeleted) {
            return std::nullopt;
        }

        std::string fileTypeStr = item.value("type", "unknown");
        std::string requestedTypeStr;
        bool matchAll = (type == FileType::ALL);

        if (!matchAll) {
            switch (type) {
                case FileType::AUDIO:
                    requestedTypeStr = "audio";
                    break;
                case FileType::IMAGE:
                    requestedTypeStr = "image";
                    break;
                case FileType::VIDEO:
                    requestedTypeStr = "video";
                    break;
                default:
                    requestedTypeStr = "unknown";
                    break; // 在 ALL 检查下不应发生
            }
            if (fileTypeStr != requestedTypeStr) {
                return std::nullopt;
            }
        }

        auto parsedInfo = FileInfo::FromJson(item);
        if (!parsedInfo) {
            EL_WARN("因索引 {} 中的解析错误跳过文件: {}", indexFilePath_, item.dump(2));
            return std::nullopt;
        }

        return parsedInfo;
    };

    for (const auto &item : indexData_) {
        if (auto info = filterFile(item)) {
            result.push_back(*info);
        }
    }

    // 排序是管理器的责任（如果合并列表）
    // std::sort(result.begin(), result.end(), ...);

    return result;
}

bool FileIndex::MarkFileAsDeleted(const std::string &fileId)
{
    std::lock_guard<std::mutex> lock(mutex_);
    bool foundAndModified = false;

    for (auto &item : indexData_) {
        if (item.value("id", "") == fileId) {
            // 只有预设文件可以被标记为已删除
            if (item.value("origin", "") != "preset") {
                EL_ERROR("无法将文件 {} 标记为已删除：它不是预设文件 (origin: {})", 
                         fileId, item.value("origin", ""));
                return false;
            }
            
            if (!item.value("is_deleted", false)) {
                item["is_deleted"] = true;
                item["last_access"] = static_cast<int64_t>(std::time(nullptr));
                foundAndModified = true;
            } else {
                EL_WARN("索引 {} 中的文件 {} 已标记为已删除。", indexFilePath_, fileId);
            }
            break; // 找到条目，退出循环
        }
    }

    if (foundAndModified) {
        return SaveIndex();
    } else {
        if (!std::any_of(indexData_.begin(), indexData_.end(),
                         [&](const auto &item) { return item.value("id", "") == fileId; })) {
            EL_WARN("在索引 {} 中未找到要标记为已删除的文件 {}。", indexFilePath_, fileId);
        }
        return false; // 未找到或已删除，无需保存
    }
}

bool FileIndex::RestoreDeletedFile(const std::string &fileId)
{
    std::lock_guard<std::mutex> lock(mutex_);
    bool foundAndModified = false;

    for (auto &item : indexData_) {
        if (item.value("id", "") == fileId) {
            // 只有预设文件可以被恢复
            if (item.value("origin", "") != "preset") {
                EL_ERROR("无法恢复文件 {}：它不是预设文件 (origin: {})", 
                         fileId, item.value("origin", ""));
                return false;
            }
            
            if (item.value("is_deleted", false)) {
                item["is_deleted"] = false;
                item["last_access"] = static_cast<int64_t>(std::time(nullptr));
                foundAndModified = true;
            } else {
                EL_WARN("索引 {} 中的文件 {} 未标记为已删除。", indexFilePath_, fileId);
            }
            break; // 找到条目，退出循环
        }
    }

    if (foundAndModified) {
        return SaveIndex();
    } else {
        if (!std::any_of(indexData_.begin(), indexData_.end(),
                         [&](const auto &item) { return item.value("id", "") == fileId; })) {
            EL_WARN("在索引 {} 中未找到要恢复的文件 {}。", indexFilePath_, fileId);
        }
        return false; // 未找到或未删除，无需保存
    }
}

bool FileIndex::RemoveFileInfo(const std::string &fileId)
{
    std::lock_guard<std::mutex> lock(mutex_);
    bool removed = false;

    for (auto it = indexData_.begin(); it != indexData_.end(); ) {
        const auto &item = *it;
        if (item.value("id", "") == fileId) {
            // 只有用户文件可以被移除
            if (item.value("origin", "") != "user") {
                EL_ERROR("无法移除文件 {}：它不是用户文件 (origin: {})", 
                         fileId, item.value("origin", ""));
                return false;
            }
            
            it = indexData_.erase(it);
            removed = true;
        } else {
            ++it;
        }
    }

    if (removed) {
        return SaveIndex();
    } else {
        EL_WARN("在索引 {} 中未找到要移除的文件 {}。", indexFilePath_, fileId);
        return false; // 未找到，无需保存
    }
}

bool FileIndex::ScanFiles(const std::string &directory, const std::string &origin)
{
    // 验证 origin 参数
    if (origin != "preset" && origin != "user") {
        EL_ERROR("ScanFiles 调用了无效的 origin: {}", origin);
        return false;
    }

    std::lock_guard<std::mutex> lock(mutex_); // 在操作期间锁定

    if (!fs::exists(directory)) {
        EL_ERROR("用于扫描的目录不存在: {}", directory);
        return false;
    }

    std::unordered_map<std::string, nlohmann::json> currentFilesByPath; // <path, item>
    std::unordered_set<std::string> fileIdsInCurrentScan;               // 跟踪在此扫描中处理的 ID

    // 将当前索引加载到 map 中以便于查找
    for (const auto &item : indexData_) {
        std::string path = item.value("path", "");
        if (!path.empty()) {
            currentFilesByPath[path] = item;
        }
    }

    // 扫描目录
    std::error_code ec;
    try {
        for (const auto &entry :
             fs::recursive_directory_iterator(directory, fs::directory_options::skip_permission_denied, ec)) {
            if (ec) {
                EL_ERROR("遍历目录 {} 时出错: {}", directory, ec.message());
                continue;
            }

            const fs::path &currentPath = entry.path();
            std::string pathStr = currentPath.string();
            fs::file_status status = fs::status(currentPath, ec);
            if (ec) {
                EL_WARN("获取 {} 的状态时出错: {}", pathStr, ec.message());
                continue;
            }

            if (fs::is_regular_file(status)) {
                std::string fileName = currentPath.filename().string();
                // 跳过隐藏文件或备份（常见模式）
                if (!fileName.empty() && (fileName[0] == '.' || fileName.find(".bak") != std::string::npos)) {
                    continue;
                }

                std::string fileId;
                auto it = currentFilesByPath.find(pathStr);
                bool isNewFile = (it == currentFilesByPath.end());

                if (isNewFile) {
                    // 在索引中未找到，添加新条目
                    fileId = GenerateUniqueId();
                    FileInfo fileInfo;
                    fileInfo.id = fileId;
                    fileInfo.name = fileName;
                    fileInfo.type = GuessFileType(pathStr);
                    fileInfo.path = pathStr;
                    fileInfo.origin = origin; // 使用提供的 origin
                    std::uintmax_t fileSize = fs::file_size(currentPath, ec);
                    fileInfo.size = ec ? 0 : static_cast<int32_t>(fileSize);
                    fileInfo.is_deleted = false;
                    fileInfo.last_access = static_cast<int64_t>(std::time(nullptr));
                    indexData_.push_back(fileInfo.ToJson());
                    fileIdsInCurrentScan.insert(fileId);
                } else {
                    // 在索引中找到，更新现有条目
                    nlohmann::json &existingItem = it->second;
                    fileId = existingItem.value("id", "");
                    fileIdsInCurrentScan.insert(fileId); // 标记为在扫描中遇到

                    // 如果 origin 不匹配，更新它
                    if (existingItem.value("origin", "") != origin) {
                         EL_WARN("在扫描 {} 期间，文件 {} 的 origin ({}) 与预期 ({}) 不匹配。将更新 origin。",
                                  directory, pathStr, existingItem.value("origin", ""), origin);
                         existingItem["origin"] = origin;
                    }

                    // 更新文件信息
                    existingItem["name"] = fileName;
                    existingItem["type"] = GuessFileType(pathStr);
                    std::uintmax_t fileSize = fs::file_size(currentPath, ec);
                    existingItem["size"] = ec ? 0 : static_cast<int32_t>(fileSize);
                    // 不要重置 is_deleted 状态；保留原始值
                    existingItem["last_access"] = static_cast<int64_t>(std::time(nullptr)); // 更新访问时间

                    // 从 map 中移除以标记为已处理
                    currentFilesByPath.erase(it);
                }
            }
        }
    } catch (const std::filesystem::filesystem_error &e) {
        EL_ERROR("扫描 {} 时文件系统错误: {}", directory, e.what());
        // 继续处理，但记录错误
    }

    // 移除在磁盘上未找到但 origin 与当前扫描匹配的条目
    indexData_.erase(
        std::remove_if(indexData_.begin(), indexData_.end(),
                       [&](const nlohmann::json &item) {
                           std::string id = item.value("id", "");
                           std::string itemOrigin = item.value("origin", "");
                           // 如果它在此扫描的 origin 中，并且未在此扫描中找到
                           return itemOrigin == origin && fileIdsInCurrentScan.find(id) == fileIdsInCurrentScan.end();
                       }),
        indexData_.end());

    return SaveIndex();
}

} // namespace FileManager
} // namespace El